package io.libp2p.example.chat;

import android.text.TextUtils;
import android.util.Base64;

import com.google.gson.Gson;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProxyPort {
    public static final String TAG = "ProxyPort";

    String socketId;

    PeerConnectHelper helper;

    Socket socket;

    OutputStream outputStream;

    Gson gson = new Gson();

    ExecutorService executors = Executors.newFixedThreadPool(1);

    volatile boolean isClosed = false;

    ProxyPortCallback callback;

    interface ProxyPortCallback{
        void onClose(String sockId);
    }

    public ProxyPort(PeerConnectHelper helper, Socket skt, ProxyPortCallback callback){
        this.helper = helper;
        socketId = UUID.randomUUID().toString();
        socket = skt;
        this.callback = callback;
    }

    public void start(){
        SocketServer.getExecutor().execute(()->{
            try {
                InputStream inputStream = socket.getInputStream();

                byte buf[] = new byte[SocketServer.BUF_SIZE];
                int len;

                while ((len = inputStream.read(buf)) != -1){
                    String base64 = Base64.encodeToString(buf, 0, len, Base64.DEFAULT);
                    DataCmd dataCmd = DataCmd.parseFileData(socketId, DataCmd.CMD_SOCKET_SERVER, base64);
                    String json = gson.toJson(dataCmd);
                    helper.sendDataChannel(json);
                }

                close();

                MyLog.I(TAG, "ProxyPort read end");
            } catch (IOException e) {
                MyLog.E(TAG, "start IOException:"+e);
                close();
            }

        });
    }

    public void writeData(DataCmd dataCmd){
        if(isClosed) return;

        if(TextUtils.equals(dataCmd.fileId, socketId)){
            executors.execute(()-> {
                byte buf[] = Base64.decode(dataCmd.zbase64, Base64.DEFAULT);

                try {
                    if (outputStream == null) {
                        outputStream = socket.getOutputStream();
                    }

                    outputStream.write(buf);
                } catch (Exception e) {
                    MyLog.E(TAG, "writeData IOException:" + e);
                    close();
                }
            });
        }
    }

    public void close(){
        MyLog.I(TAG, "socket.close() socketId=" + socketId);

        isClosed = true;

        DataCmd command = DataCmd.parseCommand(socketId, DataCmd.CMD_SOCKET_CLOSE);
        String json = gson.toJson(command);
        helper.sendDataChannel(json);

        try {
            socket.close();
        } catch (IOException e) {
            MyLog.W(TAG, "close IOException:"+e);
        }

        callback.onClose(socketId);
    }

}
